﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace A2DFramework.SQLDispatcherService
{
    public class EFRepository : IRepository
    {
        private DbContext context;

        public EFRepository(DbContext ctx)
        {
            this.context = ctx;
        }

        public virtual IEnumerable<T> Get<T>(
            Expression<Func<T, bool>> filter = null,
            Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null,
            string includeProperties = "")
            where T:class
        {
            IQueryable<T> query = context.Set<T>();

            
            if (filter != null)
            {
                query = query.Where(filter);
            }

            foreach (var includeProperty in includeProperties.Split
                (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
            {
                query = query.Include(includeProperty);
            }

            if (orderBy != null)
            {
                return orderBy(query).ToList();
            }
            else
            {
                return query.ToList();
            }
        }

        public virtual T GetByID<T>(object id)
            where T : class
        {
            return context.Set<T>().Find(id);
        }

        public virtual void Insert<T>(T entity)
            where T : class
        {
            context.Set<T>().Add(entity);
        }

        public virtual void Delete<T>(object id)
            where T : class
        {
            T entityToDelete = context.Set<T>().Find(id);
            Delete(entityToDelete);
        }

        public virtual void Delete<T>(T entityToDelete)
            where T : class
        {
            if (context.Entry(entityToDelete).State == EntityState.Detached)
            {
                context.Set<T>().Attach(entityToDelete);
            }
            context.Set<T>().Remove(entityToDelete);
        }

        public virtual void Update<T>(T entityToUpdate)
            where T : class
        {
            context.Set<T>().Attach(entityToUpdate);
            context.Entry(entityToUpdate).State = EntityState.Modified;
        }

        public virtual IEnumerable<T> GetWithRawSql<T>(string query, params object[] parameters)
            where T : class
        {
            return context.Set<T>().SqlQuery(query, parameters).ToList();
        }


        public void Save()
        {
            context.SaveChanges();
        }














        public IEnumerable<T> Get<T>(string connectionString, Expression<Func<T, bool>> filter = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, string includeProperties = "") where T : class
        {
            context.Database.Connection.ConnectionString= connectionString;

            return Get<T>(filter, orderBy, includeProperties);
        }

        public T GetByID<T>(string connectionString, object id) where T : class
        {
            context.Database.Connection.ConnectionString = connectionString;

            return GetByID<T>(id);
        }

        public void Insert<T>(string connectionString, T entity) where T : class
        {
            context.Database.Connection.ConnectionString = connectionString;

            Insert<T>(entity);
        }

        public void Delete<T>(string connectionString, object id) where T : class
        {
            context.Database.Connection.ConnectionString = connectionString;

            Delete<T>(id);
        }

        public void Delete<T>(string connectionString, T entityToDelete) where T : class
        {
            context.Database.Connection.ConnectionString = connectionString;

            Delete<T>(entityToDelete);
        }

        public void Update<T>(string connectionString, T entityToUpdate) where T : class
        {
            context.Database.Connection.ConnectionString = connectionString;

            Update<T>(entityToUpdate);
        }

        public IEnumerable<T> GetWithRawSql<T>(string connectionString, string query, params object[] parameters) where T : class
        {
            context.Database.Connection.ConnectionString = connectionString;

            return GetWithRawSql<T>(query, parameters);
        }

        public void Save(string connectionString)
        {
            context.Database.Connection.ConnectionString = connectionString;

            Save();
        }
    }
}
